package org.NooLab.itexx.retrieval;

import java.util.ArrayList;

import org.NooLab.itexx.ITexxWindowCommons;
import org.NooLab.itexx.ITexxWindowIntf;
import org.NooLab.itexx.app.config.ITexxIniPreferences;
import org.NooLab.itexx.app.controller.FoundListGenerator;
import org.NooLab.itexx.app.controller.FoundResultsGuiUpdater;
import org.NooLab.itexx.app.controller.GeneralQueueServiceIntf;
import org.NooLab.itexx.app.controller.HtmlConsumer;
import org.NooLab.itexx.app.controller.HtmlConsumerIntf;
import org.NooLab.itexx.app.controller.ScoredSerDocuments;
import org.NooLab.itexx.app.controller.SessionManager;
import org.NooLab.itexx.app.controller.content.SearchEngine;
import org.NooLab.itexx.app.controller.results.SearchEngineResultItem;
import org.NooLab.itexx.app.controller.results.SearchEngineResults;
import org.NooLab.itexx.app.gui.definition.ITexxWindowGui;
import org.NooLab.itexx.app.gui.definition.ITexxWindowGuiIntf;
import org.NooLab.itexx.stuctures.RequestFocusContext;
import org.NooLab.itexx.stuctures.RequestFocusSpec;
import org.NooLab.utilities.datatypes.IndexedDistances;
import org.NooLab.utilities.files.DFutils;
import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.objects.StringedObjects;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;



/**
 * 
 * 
 * mime types (external win32-dll):  http://mark0.net/code-tridlib-e.html
 * 
 * 
 *
 */
public class ResultsDigester {

	ITexxWindowIntf webBrowserApp ;
	ITexxWindowGuiIntf windowGui;
	ITexxWindowCommons appCommons;
	HtmlConsumerIntf htmlConsumer;
	
	boolean collectingResults=false;
	
	ArrayList<String> excludedDomains;
	StringedObjects so = new StringedObjects();
	
	PageIntf page;
	Pages pages;
	
	RequestFocusSpec requestFocus;
	
	DFutils fileutil = new DFutils(); 
	PrintLog out = new PrintLog(2,false);
	private long timeOfLastQuery=0L;
	private String lastQueryStr="";
	private String lastContextUrl="";
	
	// ========================================================================
	public ResultsDigester(ITexxWindowIntf app, boolean collectingResults) {
		
		webBrowserApp = app;
		windowGui = webBrowserApp.getWindowGui() ;
		appCommons = webBrowserApp.getAppCommons();
		htmlConsumer = appCommons.createHtmlConsumer() ;
	
		pages = new Pages(this);
		this.collectingResults = collectingResults;
		
		
		excludedDomains = appCommons.getAppProperties().getIniPreferences().getExcludedDomains() ;
	}

	// ========================================================================
	
	/**
	 * this is called by  RetrievalDispatch.handlingData()
	 */
	public void go(Object pageStrObj) {
		
		if (htmlConsumer!=null){
			out.print(3, "now going to consume the html string...");
	
			if (pageStrObj instanceof PageIntf){
				page = (PageIntf)pageStrObj ;
			}
			
		}else{
			out.printErr(2, ">>>>  no html consumer available."); return;
		}
		 
		
		// if collection, then comparing page getCollectionIndex
		int dx;
		dx = page.getExpectedCollectionSize() - page.getCurrentCollectionIndex();
		
		// TODO: Documentation here!!! collectingResults ?? purpose ???
		if ((collectingResults) && (dx>1)){
			// page objects are created as part of the retrieval, 
			// just before the WebBrowser is called for retrieval (through SwingWorker)
			pages.add(page) ;
		}else{
		
			
			RequestFocusContext  rfc = appCommons.getModelController().getRequestFocusContext() ;
			requestFocus = rfc.getRequestFocusSpec() ;
			
			// deciding about ranking , while applying filters,
			// uses focus information
			
			// splitting the google / bing page into handy items
			SearchEngineResults searchEngineResults = prepareListFromResultsPage(page);
			
			
			// note that the "searchEngineResults" contain full html info about the targeted urls
			int r = 0;
								out.print(2, "PageLoader gets feeded with the primary list of web locations...") ;			
			// now sending // putting all the items to the page loader, 
			appCommons.getPageLoader().getPagesForSearchEngineResults(searchEngineResults) ;
			// from there, the results will be transferred to the Session Manager
			// which organizes the ranking and triggers the display
			
			// now informing the RequestDispatcher that the browser could be used again for further snippets 
			appCommons.getRequestDispatcher().setDeliveredRequestDigested( page.getRequestID() ,true);
			
		}
		
		
		
	}

	private SearchEngineResults prepareListFromResultsPage(PageIntf page) {
		// 
		// we should find <ol> items !
		SearchEngineResults seResults=null;
		Elements contentListItems; 
		Element hlistItem , href ;
		
		String itemSelectionTag ="";
		String itemTitle,hrefUrl,itemText,listItemName,str, rawItemHtml,_html = page.getHTML();
		boolean hb ;
		
		
		Document soupdoc = Jsoup.parse(_html);	
									// 
									// fileutil.writeFileSimple( fileutil.gettempfile("prepGoogle.txt"), _html);
									
		// select the item marker dependent of the domain of the query url!!
		// we need an object checking for that, since we need the variant settings from preferences.txt!!
		// both are not functioning so far
		 
		SearchEngine se = appCommons.getSearchEngines().getSearchEngineByUrl( page.getContextUrl() );
		
		if (se==null){
			appCommons.getWindowGui().setStatusLabelText("No maching search engine definition found in preferences.");
			out.delay(1500) ;
			return seResults;
		}
		
		itemSelectionTag = se.getMappedItem("item",true); 
		
		if (itemSelectionTag.length()==0){
			appCommons.getWindowGui().setStatusLabelText("Tag (item selection) not found for identified searchengine ("+se.getName()+")");
			out.delay(1500) ;
			return seResults;
		}
		/*
		if (page.getContextUrl().contains("www.google")){
			itemSelectionTag = "li.g" ;
		}
		if (page.getContextUrl().contains("www.bing")){
			itemSelectionTag = "???" ;
		}
		*/
		
		contentListItems = soupdoc.select( itemSelectionTag); // e.g. ("li.g"); jsoup is inert against capitals...
		
		seResults = new SearchEngineResults( appCommons, this );
		
		
		String requestid = page.getRequestID() ;
		String quStr = appCommons.getSessionManager().getRequestHistory().get( requestid ).getRequestStr() ;
        									out.printErr(2, "Query identifier (P) : "+ quStr);
        
		// we should do this elsewhere.. we could as different search engines 
		long timeSinceLastQuery = System.currentTimeMillis() - timeOfLastQuery ;
		if ((quStr.contentEquals(lastQueryStr)) && (timeSinceLastQuery<5000) && (lastContextUrl.contentEquals( page.getContextUrl()))){
			quStr = "" ;
		}
		lastQueryStr = quStr;
		timeOfLastQuery = System.currentTimeMillis() ;
		lastContextUrl = page.getContextUrl() ; // e.g. search engine query url
		
		if ((quStr==null) || (quStr.length()<=1)){
			return seResults;
		}
		
		
		
		
		for (int i=0;i<contentListItems .size();i++){
			
			try{
			

				hlistItem = contentListItems.get(i);
				
				href      = hlistItem.select("a[href]").first();
				hrefUrl   = href.attr("abs:href"); // url of link
				itemTitle = href.text() ; // text on link surface == title
				
				// this is only valid for Google... we need an abstraction here, and 
				// the markers should be taken from external config file
				itemText  = hlistItem.select("span.st").first().text(); 
				
				// rawItemHtml = hlistItem.html(); 
				// itemText    = hlistItem.text();
				listItemName = hlistItem.tagName();
				
				// requestFocus is set therein by reference to the master object in ModelController
				SearchEngineResultItem seResultItem = new SearchEngineResultItem(seResults);
				
				// seResultItem
				seResultItem.setTargetDocUrl(hrefUrl) ;        
				//                           page.getPackageID() !!! this contains the request id that identifies the query of the user
				seResultItem.setRequestguid( page.getRequestID() ); // this is the guid of the delivery package ! not of the request id
				seResultItem.setSeText( itemText );
				seResultItem.setDisplayedSummaryAbstract( itemText ) ; // by default the same, yet it is likely to get changed
				seResultItem.setSeTitle( itemTitle ) ;
				
						String pkgGuid = page.getPackageID();
						

				seResultItem.setSeQuery(quStr);
				seResultItem.setRequestFocus(requestFocus);  // important for scoring
				
				
				seResultItem.finalizeContent() ;
				
				// is the result from an excluded domain?
				boolean excluded=false;
				if ((excludedDomains!=null) && (excludedDomains.size()>0)){
					String ds = appCommons.strgutil.getDomainFromUrl(hrefUrl);
					hb = excludedDomains.indexOf(ds)>=0;
				}
				// is it double?
				if (excluded==false){
					hb = checkListForUrl( seResults, hrefUrl );
					if (hb){
						excluded=true;
					}
				}
				
				//
				
				if ((excluded==false) && (quStr!=null) && (quStr.length()>1)){
					seResults.add(seResultItem) ; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
					// adding to SearchEngineResults, 
					// next step then is to provide it to the PageLoader
				}else{
					continue;
				}

			}catch(Exception e){
				String estr = ""+e.getMessage();
			}
			
		}// i->
		
		
		if (appCommons.getAppProperties().getIniPreferences().getShowRawSer()>0){
			out.print(3, "");
			// new RawSerListFeed( appCommons, seResults);
		}

		return seResults;
	}

	 

	private boolean checkListForUrl(SearchEngineResults seResultsList, String urlStr ) {

		boolean rB= false;
		SearchEngineResultItem seri;
		
		
		for (int i=0;i<seResultsList.size();i++){
			seri = seResultsList.get(i);
			if (urlStr.contentEquals(seri.getTargetDocUrl())){
				rB=true;
				break;
			}
		}//i->
		
		return rB;
	}

	private int determineRanking(SearchEngineResults searchEngineResults) {
		// calculates tf-idf , uses partially also external resources (ITEXX!!!)
		
		int result = -1;
		if (searchEngineResults==null){
			return result;
		}
		
		
		
		return result;
	}
	
	
	

}


class RawSerListFeed implements GeneralQueueServiceIntf{

	ScoredSerDocuments rawSerItems;
	SessionManager smgr ;
	FoundListGenerator foundListGenerator ;
	private IndexedDistances panelMap;
	private FoundResultsGuiUpdater guiUpdater;
	
	// ------------------------------------------------------------------------
	public RawSerListFeed(  ITexxWindowCommons appCommons,
							SearchEngineResults seResults) {
		// 
		SearchEngineResultItem ser ;
		
		smgr = appCommons.getSessionManager() ;
		
		panelMap = appCommons.getModelController().getPanelMap() ;
		guiUpdater = appCommons.getResultsGuiUpdater();
		
		// we feed the raw results only, if the panelMap is still empty!!
		
		if (panelMap.size()>=-1){ // <<<<<<<<<<<<<  change that for activation...
			return;
		}

		// 
		foundListGenerator = new FoundListGenerator(smgr, (GeneralQueueServiceIntf)this) ;

		rawSerItems = new  ScoredSerDocuments(smgr) ;
		
		for (int i=0;i<seResults.size();i++){
			ser = seResults.get(i);
			ser.setScore(((double)i)/1000.0);
			rawSerItems.introduceSerItem( ser);
		}
		int n = rawSerItems.getFreshItemsIndices().size();
		
		// 
		foundListGenerator.updateRawResults(rawSerItems);
	}
	// ------------------------------------------------------------------------
	

	@Override
	public void setSubProcessFinished(boolean flag) {
		// 
	}

	@Override
	public void setSubProcessFailed(boolean flag) {
		// 
	}
	
	
}
